
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <direct.h>
#include <io.h>

/*
 This program scans the headers in the gsl subdirectory for 
 data that needs to be exported from the DLL versions of
 gsl and cblas and writes the two definition files that are
 needed for DLL generation.  The header files are not modified
*/

void process_file(FILE *inf, FILE *gslf, FILE *blsf)
{   char buf[4096], *bp, *b0, *b1, *p_sym[5], *q_sym[5], *nl0, *nl1;
    int n_sym = 0, in_sym = 0, in_pars = 0, in_fun = 0, in_com = 0,
        in_data = 0, in_inhib = 1, cb = 0, sep, lsep, t, ch;

    nl0 = bp = buf; ch = fgetc(inf);
    while(!feof(inf) && ch != EOF)
    {
        *bp = ch;
        if(in_com)
        {
            if(bp > buf && ch == '/' && *(bp - 1) == '*')
                in_com = 0;
            ++bp;
        }
        else if(in_pars)
        {
            if(ch == '(')
                ++cb;
            else if(ch == ')' && !cb--)
            {
                in_pars = 0; cb = 0;
                if(n_sym > 1)
                    in_fun = 1;
            }
            ++bp;
        }
        else if(in_sym)
        {
            if(!iscsym(ch))
            {
                q_sym[n_sym - 1] = bp;
                in_sym = 0;
                lsep = sep; sep = 1;
                if(!strncmp(p_sym[n_sym - 1], "GSL_VAR", 7))
                    in_data = 1;
                if(!strncmp(p_sym[n_sym - 1], "inline", 6))
                    in_inhib = 1;
                if(!strncmp(p_sym[n_sym - 1], "typedef", 7))
                    in_inhib = 1;
                if(!strncmp(p_sym[n_sym - 1], "__BEGIN_DECLS", 13))
                    if(p_sym[n_sym - 1] == nl0)
                        in_inhib = 0;
                continue;
            }
            ++bp;
        }
        else if(ch == '(')
        {
            in_pars = 1; ++bp;
        }
        else if(iscsym(ch))
        {
            if(n_sym < 5)
                p_sym[n_sym++] = bp++;
            else
            {
                t = q_sym[0] - buf; b0 = q_sym[0];
                p_sym[0] = p_sym[1] - t;
                q_sym[0] = q_sym[1] - t;
                p_sym[1] = p_sym[2] - t;
                q_sym[1] = q_sym[2] - t;
                p_sym[2] = p_sym[3] - t;
                q_sym[2] = q_sym[3] - t;
                p_sym[3] = p_sym[4] - t;
                q_sym[3] = q_sym[4] - t;
                nl0 -= t;
                nl1 -= t;
                b1 = buf;
                while(b0 < bp)
                    *b1++ = *b0++;
                *b1 = *bp;
                bp = b1;
                p_sym[n_sym - 1] = bp;
                ++bp;
            }
            in_sym = 1;
        }
        else if(ch == ';')
        {
            b0 = buf;
            if(!in_inhib && n_sym > 1 && (in_fun && lsep || in_data))
            {
                if(!strncmp(p_sym[n_sym - 1], "gsl_", 4))
                {
                    if(q_sym[n_sym - 2] - p_sym[n_sym - 2] != 2
                        || strncmp(p_sym[n_sym - 2], "do", 2))
                    {
                        fprintf(gslf, "\n\t");
                        b0 = p_sym[n_sym - 1];
                        b1 = q_sym[n_sym - 1];
                        while(b0 < b1)
                            fputc(*b0++, gslf);
                        if(in_data)
                            fprintf(gslf, " DATA");
                    }
                }
                if(!strncmp(p_sym[n_sym - 1], "cblas_", 6))
                {
                    if(q_sym[n_sym - 2] - p_sym[n_sym - 2] != 2
                        || strncmp(p_sym[n_sym - 2], "do", 2))
                    {
                        fprintf(blsf, "\n\t");
                        b0 = p_sym[n_sym - 1];
                        b1 = q_sym[n_sym - 1];
                        while(b0 < b1)
                            fputc(*b0++, blsf);
                        if(in_data)
                            fprintf(blsf, " DATA");
                    }
                }
            }
            bp = buf; n_sym = 0; in_fun = in_data = in_inhib = 0;
        }
        else if(bp > buf && ch == '*' && *(bp - 1) == '/')
        {
            in_com = 1;
            ++bp;
        }
        else if(!strchr("*& \t\r\n", ch))
        {
            sep = 0; ++bp;
        }
        else if(ch == '\r' || ch == '\n')
        {
            ++bp; nl1 = nl0; nl0 = bp;
        }
        else
            ++bp;
        ch = fgetc(inf);
    }
}

int main(void)
{   struct _finddata_t cfile;
    intptr_t hfile;
    FILE *inf, *gslf, *blsf;
    char nbuf[128], *dir, *p;

    if((gslf = fopen("gsl.def", "w")) == 0)
    {
        printf("\nFile open error on: gsl.def for writing"); exit(-1);
    }

    if((blsf = fopen("cblas.def", "w")) == 0)
    {
        printf("\nFile open error on: cblas.def for writing"); exit(-1);
    }

    fprintf(gslf, "LIBRARY gsl\nEXPORTS");
    fprintf(blsf, "LIBRARY cblas\nEXPORTS");
    if((dir = _getcwd( NULL, 0 )) == NULL )
    {
        printf("\ndirectory error\n"); exit(-1);
    }

    if((p = strrchr(dir, '\\')) || (p = strrchr(dir, '/')))
    {
        if(!strncmp(++p, "gsl.vc", 6))
        {
            strcpy(p, "gsl");
            printf("\nworking directory: %s ", dir);
            if(_chdir(dir))
            {
                printf("n not found\n\n"); exit(-1);
            }
            else
                printf("\n");
            free(dir);
        }
    }

    if((hfile = _findfirst( "gsl_*.h", &cfile )) == -1L )
    {
        printf( "\nNo gsl_*.h files in the working directory\n" ); exit(-1);
    }

    do
    {
        if((inf = fopen(cfile.name, "r")) == 0)
        {
            printf("\nFile open error on %s for reading", cfile.name); break;
        }

        process_file(inf, gslf, blsf);
        fclose(inf);
    }
    while
        ( _findnext( hfile, &cfile ) == 0 );

    _findclose( hfile );
    fprintf(gslf, "\n"); fclose(gslf);
    fprintf(blsf, "\n"); fclose(blsf);
    printf("\n\n");
    return 0;
}
